/*******************************************************************************
# Linux-UVC streaming input-plugin for MJPG-streamer                           #
#                                                                              #
# This package work with the Logitech UVC based webcams with the mjpeg feature #
#                                                                              #
# Copyright (C) 2005 2006 Laurent Pinchart &&  Michel Xhaard                   #
#                    2007 Lucas van Staden                                     #
#                    2007 Tom St枚veken                                         #
#                                                                              #
# This program is free software; you can redistribute it and/or modify         #
# it under the terms of the GNU General Public License as published by         #
# the Free Software Foundation; either version 2 of the License, or            #
# (at your option) any later version.                                          #
#                                                                              #
# This program is distributed in the hope that it will be useful,              #
# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
# GNU General Public License for more details.                                 #
#                                                                              #
# You should have received a copy of the GNU General Public License            #
# along with this program; if not, write to the Free Software                  #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA    #
#                                                                              #
*******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
//#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <signal.h> 
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <pthread.h>
#include <syslog.h>

#include "fmjpeg.h"
#include "fmjpeg_avcodec.h"
#include "../../utils.h"
#include "../../mjpg_streamer.h"

/* private functions and variables to this plugin */
static pthread_t   worker;
static globals     *pglobal;
static pthread_mutex_t controls_mutex;

extern void* thread_function(void*);

extern video_profile           video_setting;
extern unsigned char        yuv_format;
extern unsigned char           *video_buf_virt;
extern unsigned char           *out_virt_buffer;
extern unsigned char           mmap_addr;
extern unsigned int            mmap_done;
extern int video_fd;


/*** plugin interface functions ***/
/******************************************************************************
Description.: This function initializes the plugin. It parses the commandline-
              parameter and stores the default and parsed values in the
              appropriate variables.
Input Value.: param contains among others the command-line string
Return Value: 0 if everything is fine
              1 if "--help" was triggered, in this case the calling programm
              should stop running and leave.
******************************************************************************/
int input_init(input_parameter *param) 
{
    printf("input_init start\n");
    printf("param->parameter_string=%s\n", param->parameter_string);
    pglobal = param->global;
    
    fmjpeg_init();
    return 0;
}

/******************************************************************************
Description.: Stops the execution of worker thread
Input Value.: -
Return Value: always 0
******************************************************************************/
int input_stop(void) 
{
    printf("input_stop start\n");
    return 0;
}



/******************************************************************************
Description.: process commands, allows to set certain runtime configurations
              and settings like pan/tilt, colors, saturation etc.
Input Value.: * cmd specifies the command, a complete list is maintained in
                the file "input.h"
              * value is used for commands that make use of a parameter.
Return Value: depends in the command, for most cases 0 means no errors and
              -1 signals an error. This is just rule of thumb, not more!
******************************************************************************/
int input_cmd(in_cmd_type cmd, int value) 
{
    printf("input_cmd start\n");
    return 0;
}

/******************************************************************************
Description.: spins of a worker thread
Input Value.: -
Return Value: always 0
******************************************************************************/
int input_run(void) 
{
    pthread_t pthread_t_input;
    printf("input_run start\n");
    
    pglobal->buf = malloc(256*1024);
    if (pglobal->buf == NULL) {
      fprintf(stderr, "could not allocate memory\n");
      exit(EXIT_FAILURE);
    }

  
    if(pthread_create(&pthread_t_input, 0, thread_function, NULL) != 0)
    {
	free(pglobal->buf);
	pglobal->buf = NULL;
	printf("创建线程错误\n");
	exit(EXIT_FAILURE);
    }
    pthread_detach(pthread_t_input);
    return 0;
}

/******************************************************************************
Description.: this functions cleans up allocated ressources
Input Value.: arg is unused
Return Value: -
******************************************************************************/
void fmjpeg_cleanup(void *arg) {
  static unsigned char first_run=1;

  if ( !first_run ) {
    DBG("already cleaned up ressources\n");
    return;
  }

  first_run = 0;
  DBG("cleaning up ressources allocated by input thread\n");

  if (pglobal->buf != NULL) free(pglobal->buf);
  
  DBG("fmjpeg_uninit \n");
  fmjpeg_uninit();
}

void* thread_function(void* arg)
{
    FILE* fp;
    int i = 1;
    char filename[40];
    long lSize;
    printf("thread_function start\n");

    /* set cleanup handler to cleanup allocated ressources */
    pthread_cleanup_push(fmjpeg_cleanup, NULL);
  
    while(!pglobal->stop)
    {
#if 0
	if(i>12) i=1;
	
	sprintf(filename, "./clock/clock%d.jpg", i++);
	fp = fopen(filename, "rb");
	if(fp == NULL)
	{
	    continue;
	}
	
	fseek (fp , 0 , SEEK_END);  
	lSize = ftell(fp);
#endif
	/* copy JPG picture to global buffer */
	pthread_mutex_lock( &pglobal->db );
	
#if 0
	printf("%d,lSize=%ld\n", i, lSize);
	fseek(fp, SEEK_SET, 0);
	fread(pglobal->buf, lSize, 1, fp);
	pglobal->size = lSize;
#else
    pglobal->size = encode_video(&video_setting, out_virt_buffer);      
#if 1
    memcpy(pglobal->buf, out_virt_buffer, pglobal->size);
#endif
    //fwrite((void *)out_virt_buffer,blength,1,dout);  
    usleep(1*1000);  		
#endif

#if 0
	for(i=0;i<20;i++)
	{
	    printf("%x ", pglobal->buf[i]);
	}
	printf("\n\n");
#endif

#if 0
	fclose(fp);
#endif
	/* signal fresh_frame */
	pthread_cond_broadcast(&pglobal->db_update);
	pthread_mutex_unlock( &pglobal->db );
#if 0
	usleep(1000*1000);
#endif
    }
    
    IPRINT("leaving input thread, calling cleanup function now\n");
    pthread_cleanup_pop(1);
    return NULL;
}

int fmjpeg_uninit()
{
    if ( mjpeg_close(&video_setting) < 0 )
        printf("mjpeg_close fail\n");		
		
    free(out_virt_buffer);	
		
    close(video_fd);
    
    return 0;
}

int fmjpeg_init()
{
    int ret, i;    
    unsigned int blength;
    char    dout_name[30];
    FILE    *dout;	
//    int optindex;	
#if 0
    if(argc<3) {
        		printf("Usage: \n");
        		printf("     jpeg_main -f 0: initization without ROI and MP4 2D YUV\n");
		printf("     jpeg_main -f 1: initization without ROI and Jpg sequencial YUV\n");		
        		printf("     jpeg_main -r 0: initization with ROI and MP4 2D YUV\n");
		printf("     jpeg_main -r 1: initization with ROI and Jpg sequencial YUV\n");	
		return 0;
    }
     if (argc > 2)     {
        // something simple for now

	if (strcmp("-f", argv[1]) == 0)
		video_setting.roi_enable = 0;
	else if (strcmp("-r", argv[1]) == 0)
		video_setting.roi_enable = 1;
	yuv_format = atoi(argv[2]);

    }
#endif
    video_setting.roi_enable = 1;
    yuv_format = 1;  // 0 for mp4, 1 for jpg, 2 for h264
    //set the default value
    video_setting.qmax = 31;
    video_setting.qmin = 1;
    video_setting.quant = 31;
    video_setting.bit_rate = 512*2;
    video_setting.width = 720;
    video_setting.height = 480;
    video_setting.framerate = 30;  
    video_setting.frame_rate_base = 1;
    video_setting.gop_size = 30;
    video_setting.fmjpeg_image_quality=30;      //need assign by UI
    video_setting.u32RestartInterval=10;        //need assign by UI
    video_setting.fmjpeg_jpeg=1;        		//0 for motion JPEG, 1 for JPEG
    video_setting.fmjpeg_yuv_format=0;           //0 for YUV420	
    video_setting.YUV_2D = yuv_format;            // 0 for mp4, 1 for jpg, 2 for h264

    video_setting.roi_left_x=ROI_LEFT_X;
    video_setting.roi_left_y=ROI_LEFT_Y;
    video_setting.roi_right_x=ROI_RIGHT_X;
    video_setting.roi_right_y=ROI_RIGHT_Y;


	
    out_virt_buffer = (unsigned char *) malloc(video_setting.width * video_setting.height * 3/2);	
   	
    if((ret=v4l_init(&video_setting)) < 0)
        return -1;

    if(mjpeg_init(&video_setting)<0)
        return -1;
#if 0
    for(i=0;i<5;i++)  {
	if ( video_setting.roi_enable) {
		video_setting.roi_right_x = ROI_RIGHT_X + i*32;
		video_setting.roi_right_y = ROI_RIGHT_Y + i*32;
		video_setting.roi_left_x = ROI_LEFT_X + i*32;
		video_setting.roi_left_y = ROI_LEFT_Y + i*32;
	}
	}
#endif
    return 0;
}

#if 0
int main1(int argc, char **argv)
{
    int ret, i;    
    unsigned int blength;
    char    dout_name[30];
    FILE    *dout;	
//    int optindex;	
    if(argc<3) {
        		printf("Usage: \n");
        		printf("     jpeg_main -f 0: initization without ROI and MP4 2D YUV\n");
		printf("     jpeg_main -f 1: initization without ROI and Jpg sequencial YUV\n");		
        		printf("     jpeg_main -r 0: initization with ROI and MP4 2D YUV\n");
		printf("     jpeg_main -r 1: initization with ROI and Jpg sequencial YUV\n");	
		return 0;
    }
     if (argc > 2)     {
        // something simple for now

	if (strcmp("-f", argv[1]) == 0)
		video_setting.roi_enable = 0;
	else if (strcmp("-r", argv[1]) == 0)
		video_setting.roi_enable = 1;
	yuv_format = atoi(argv[2]);

    }
   	 
    //set the default value
    video_setting.qmax = 31;
    video_setting.qmin = 1;
    video_setting.quant = 0;
    video_setting.bit_rate = 512;
    video_setting.width = 720;
    video_setting.height = 480;
    video_setting.framerate = 5;
    video_setting.frame_rate_base = 1;
    video_setting.gop_size = 30;
    video_setting.fmjpeg_image_quality=40;      //need assign by UI
    video_setting.u32RestartInterval=10;        //need assign by UI
    video_setting.fmjpeg_jpeg=1;        		//0 for motion JPEG, 1 for JPEG
    video_setting.fmjpeg_yuv_format=0;           //0 for YUV420	
    video_setting.YUV_2D = yuv_format;            // 0 for mp4, 1 for jpg, 2 for h264

    video_setting.roi_left_x=ROI_LEFT_X;
    video_setting.roi_left_y=ROI_LEFT_Y;
    video_setting.roi_right_x=ROI_RIGHT_X;
    video_setting.roi_right_y=ROI_RIGHT_Y;


	
    out_virt_buffer = (unsigned char *) malloc(video_setting.width * video_setting.height * 3/2);	
   	
    if((ret=v4l_init(&video_setting)) < 0)
        return -1;

    if(mjpeg_init(&video_setting)<0)
        return -1;

    for(i=0;i<5;i++)  {
	if ( video_setting.roi_enable) {
		video_setting.roi_right_x = ROI_RIGHT_X + i*32;
		video_setting.roi_right_y = ROI_RIGHT_Y + i*32;
		video_setting.roi_left_x = ROI_LEFT_X + i*32;
		video_setting.roi_left_y = ROI_LEFT_Y + i*32;
	}
        if ( video_setting.roi_enable) {
	   if ( yuv_format == 0)		
	          sprintf(dout_name,"/tmp/share/mp4yuv_roi%d.jpg",i);
	   else if ( yuv_format == 1)
	   	 sprintf(dout_name,"/tmp/share/jpgyuv_roi%d.jpg",i);
	   else if ( yuv_format == 2)
	   	 sprintf(dout_name,"/tmp/share/h264yuv_roi%d.jpg",i);
        } else {		
            if ( yuv_format == 0)		
	          sprintf(dout_name,"/tmp/share/mp4yuv_img%d.jpg",i);
	   else if ( yuv_format == 1)
	   	 sprintf(dout_name,"/tmp/share/jpgyuv_img%d.jpg",i);
	   else if ( yuv_format == 2)
	   	 sprintf(dout_name,"/tmp/share/h264yuv_img%d.jpg",i);
        	}		
        dout=fopen(dout_name,"wb");
        printf("Use output name %s\n",dout_name);fflush(stdout);        
        blength = encode_video(&video_setting);      
        fwrite((void *)out_virt_buffer,blength,1,dout);    		
        fclose(dout);
    }

  	
    if ( mjpeg_close(&video_setting) < 0 )
        printf("mjpeg_close fail\n");		
		
    free(out_virt_buffer);	
		
    close(video_fd);
		
    return 0;
}
#endif
